home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 23 / CU Amiga - Super CD-ROM 23 (June 1998).iso / CUCD / Programming / OUI / fbutton.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  16.8 KB  |  578 lines

  1. //$Id: fbutton.cc 1.4 1998/04/08 15:11:45 dlorre Exp dlorre $
  2. #include <intuition/intuition.h>
  3. #include <intuition/classes.h>
  4. #include <intuition/classusr.h>
  5. #include <intuition/imageclass.h>
  6. #include <intuition/gadgetclass.h>
  7. #include <intuition/icclass.h>
  8. #include <intuition/cghooks.h>
  9. #include <libraries/gadtools.h>
  10.  
  11. #include <string.h>
  12. #include <stdio.h>
  13. #include <mydebug.h>
  14.  
  15. #include "screen.h"
  16. #include "window.h"
  17. #include "gadgets/fbutton.h"
  18. #include "gadgets/eclass.h"
  19. #include "gadgetlist.h"
  20.  
  21. #include <proto/exec.h>
  22. #include <proto/dos.h>
  23. #include <proto/graphics.h>
  24. #include <proto/intuition.h>
  25. #include <proto/utility.h>
  26. #include <clib/alib_protos.h>
  27. #include <compiler.h>
  28.  
  29. static int InitBoxImage(void) ;
  30. static void FreeBoxImage(void) ;
  31. static struct Image *BoxImage ;
  32.  
  33.  
  34. // Ces déclarations ne sont plus statiques puisque la classe devient globale
  35.  
  36. Class *BOOPSIfbutton ;
  37. int InitFButton(void) ;
  38. void FreeFButton(void) ;
  39.  
  40. extern "C" STDARGS ULONG HookEntry() ;
  41.  
  42.  
  43. // ========================================================================
  44. // ========================== FBUTTON CLASS ===============================
  45. // ========================================================================
  46.  
  47. fbutton::fbutton(gadgetlist *gl,
  48.                void (window::*func)(gadget *, unsigned long, unsigned short),
  49.                const char *t, BOOL def, BOOL disable) : gadget(gl, func),
  50.                                         it1(NULL), it2(NULL), it3(NULL),
  51.                                         norm1(NULL), norm2(NULL), under(NULL),
  52.                                         font(NULL), underline(NULL)
  53. {
  54.     InitBoxImage() ;
  55.     InitFButton() ;
  56.  
  57.     if (t) {
  58.         if (def) glist->setdefault(TRUE) ;
  59.         initlab(t) ;
  60.     }
  61.  
  62.     gad = gl->gad = (Gadget *)NewObject(BOOPSIfbutton, NULL,
  63.             GA_ID,          id,
  64.             GA_Top,         gl->ng->ng_TopEdge,
  65.             GA_Left,        gl->ng->ng_LeftEdge,
  66.             GA_Width,       gl->ng->ng_Width,
  67.             GA_Height,      gl->ng->ng_Height,
  68.  
  69.             GA_Immediate,   TRUE,
  70.             GA_RelVerify,   TRUE,
  71.  
  72.             GA_Previous,    gl->gad,
  73.             GA_IntuiText,   it1 ,
  74.             GA_Image,       BoxImage,
  75.  
  76.             GA_UserData,    EGA_Pulse,
  77.             GA_Disabled,    disable,
  78.             EGA_XPens,      gl->win->ws->xpens,
  79.  
  80.             TAG_END) ;
  81.  
  82.     if (def) gl->setdefault(FALSE) ;
  83. }
  84.  
  85. fbutton::~fbutton()
  86. {
  87.     freelab() ;
  88.     if (gad) DisposeObject(gad) ;
  89.     FreeFButton() ;
  90.     FreeBoxImage() ;
  91. }
  92.  
  93. void fbutton::select(BOOL sel, BOOL disable)
  94. {
  95.     SetGadgetAttrs((Gadget *)gad, w, NULL,
  96.         GA_Selected,    sel,
  97.         GA_Disabled,    disable,
  98.         TAG_END) ;
  99.     RefreshGList((Gadget *)gad, w, NULL, 1);
  100. }
  101.  
  102.  
  103. void fbutton::keystroke(BOOL shifted)
  104. {
  105.     select(TRUE) ;
  106.     Delay(5) ;
  107.     select(FALSE) ;
  108.     Delay(5) ;
  109.     gadget::action(NULL, NULL) ;
  110. }
  111.  
  112. void fbutton::action(unsigned long classe, unsigned short code)
  113. {
  114.     if (classe != IDCMP_GADGETDOWN) {
  115.         gadget::action(classe, code) ;
  116.     }
  117. }
  118.  
  119.  
  120. void fbutton::initlab(const char *t)
  121. {
  122. BOOL    underset = FALSE ;
  123. int     i, l1, l2 ;
  124.  
  125.     if (t) {
  126.  
  127.         it1 = new IntuiText ;
  128.         it2 = new IntuiText ;
  129.         it3 = new IntuiText ;
  130.  
  131.         underline = new TTextAttr ;
  132.  
  133.         it1->FrontPen = it2->FrontPen = it3->FrontPen = glist->gpen ;
  134.         it1->BackPen = it2->BackPen = it3->BackPen = 0 ;
  135.         it1->DrawMode = it2->DrawMode = it3->DrawMode = JAM1 ;
  136.  
  137.         norm1 = new char[strlen(t)+1] ;
  138.         norm2 = new char[strlen(t)+1] ;
  139.         under = new char[2] ;
  140.  
  141.         underkey(t) ;
  142.  
  143.         CopyMem(glist->ng->ng_TextAttr, underline, sizeof(struct TTextAttr)) ;
  144.         underline->tta_Style |= FSF_UNDERLINED ;
  145.         font = OpenFont((TextAttr *)underline) ;
  146.  
  147.         for (i=l1=l2=0; t[i]; i++) {
  148.             if (t[i] == '_') {
  149.                 if (t[i+1]) under[0] = t[++i] ;
  150.                 underset = TRUE ;
  151.             }
  152.             else {
  153.                 if (underset) {
  154.                     norm2[l2++] = t[i] ;
  155.                 }
  156.                 else {
  157.                     norm1[l1++] = t[i] ;
  158.                 }
  159.             }
  160.         }
  161.         norm1[l1] = '\0' ;
  162.         norm2[l2] = '\0' ;
  163.         under[1] = '\0' ;
  164.  
  165.         if (l1) {
  166.             it1->IText = (UBYTE *)norm1 ;
  167.             it1->ITextFont = glist->ng->ng_TextAttr ;
  168.             if (underset) {
  169.                 it1->NextText = it2 ;
  170.                 it2->LeftEdge = short(IntuiTextLength(it1)) ;
  171.                 it2->IText = (UBYTE *)under ;
  172.                 it2->ITextFont = (TextAttr *)underline ;
  173.                 if (l2) {
  174.                     it2->NextText = it3 ;
  175.                     it3->LeftEdge = short(it2->LeftEdge + IntuiTextLength(it2)) ;
  176.                     it3->IText = (UBYTE *)norm2 ;
  177.                     it3->ITextFont = glist->ng->ng_TextAttr ;
  178.                 }
  179.             }
  180.         }
  181.         else if (underset) {
  182.             it1->IText = (UBYTE *)under ;
  183.             it1->ITextFont = (TextAttr *)underline ;
  184.             it1->NextText = it2 ;
  185.             it2->LeftEdge = short(IntuiTextLength(it1)) ;
  186.             it2->IText = (UBYTE *)norm2 ;
  187.             it2->ITextFont = glist->ng->ng_TextAttr ;
  188.         }
  189.     }
  190. }
  191.  
  192.  
  193. void fbutton::freelab()
  194. {
  195.     if (norm1) delete norm1 ;
  196.     if (norm2) delete norm2 ;
  197.     if (under) delete under ;
  198.  
  199.     if (it1) delete it1 ;
  200.     if (it2) delete it2 ;
  201.     if (it3) delete it3 ;
  202.  
  203.     if (underline) delete underline ;
  204.  
  205.     if (font) CloseFont(font) ;
  206. }
  207.  
  208.  
  209. void fbutton::set(const char *text)
  210. {
  211.     if (text) {
  212.     freelab() ;
  213.     initlab(text) ;
  214.     SetGadgetAttrs((Gadget *)gad, w, NULL,
  215.         GA_IntuiText,    it1,
  216.         TAG_END) ;
  217.     }
  218. }
  219.  
  220.  
  221. static int BoxImageCnt = 0 ;
  222. int InitBoxImage(void)
  223. {
  224.     if (BoxImageCnt) {
  225.         BoxImageCnt++ ;
  226.     }
  227.     else if (
  228.         BoxImage = (struct Image *)NewObject(NULL, (UBYTE *)FRAMEICLASS,
  229.         IA_FrameType,   FRAME_BUTTON,
  230.         IA_EdgesOnly,   TRUE,
  231.         TAG_END)) {
  232.         BoxImageCnt = 1 ;
  233.     }
  234.     else
  235.         BoxImageCnt = 0 ;
  236.  
  237.     return (BoxImageCnt) ;
  238. }
  239.  
  240. void FreeBoxImage(void)
  241. {
  242.     BoxImageCnt-- ;
  243.     if (!BoxImageCnt) {
  244.         // This is a DEFENSIVE programming test
  245.         // i.e. not needed under normal conditions
  246.         if (BoxImage) DisposeObject(BoxImage) ;
  247.     }
  248. }
  249.  
  250.  
  251. // ========================================================================
  252. // =============================== FBUT ===================================
  253. // ========================================================================
  254.  
  255. #define DRAW_NONE       0
  256. #define DRAW_IMAGE      1
  257. #define DRAW_INTUITEXT  2
  258. #define DRAW_TEXT       3
  259.  
  260. struct FButtonINST {
  261.     Image       *LabelImage ;
  262.     Image       *Img ;
  263.     IntuiText   *IText ;
  264.     STRPTR      Text ;
  265.     LONG        Mode ;
  266.     UWORD       *XPens ;
  267. } ;
  268.  
  269. static ULONG STDARGS dispatchFButton(Class *cl, Object *o, Msg msg);
  270.  
  271. static void    NotifyFButton(Class *, Object *, ULONG, long, gpInput *) ;
  272.  
  273. static ULONG   RenderFButton(Class *, Gadget *, gpRender *) ;
  274.  
  275. static void    FButtonLims(FButtonINST *inst, Gadget *g, GadgetInfo *gi) ;
  276.  
  277. static int FButtonCnt = 0 ;
  278.  
  279. static UWORD ditherData[] = { 0x5555, 0xAAAA } ;
  280.  
  281. int InitFButton(void)
  282. {
  283.     if (FButtonCnt) {
  284.         FButtonCnt++ ;
  285.     }
  286.     else if (!(BOOPSIfbutton = MakeClass(NULL, (UBYTE *)GADGETCLASS, NULL,
  287.         sizeof(FButtonINST), 0))) {
  288.         FButtonCnt = 0 ;
  289.     }
  290.     else {
  291.         BOOPSIfbutton->cl_Dispatcher.h_Entry = (HOOKFUNC)HookEntry ;
  292.         BOOPSIfbutton->cl_Dispatcher.h_SubEntry = (HOOKFUNC)dispatchFButton;
  293.         BOOPSIfbutton->cl_Dispatcher.h_Data = NULL ;
  294.         FButtonCnt = 1 ;
  295.     }
  296.     return FButtonCnt ;
  297. }
  298.  
  299. void FreeFButton(void)
  300. {
  301.     FButtonCnt-- ;
  302.     if (!FButtonCnt)
  303.         if (BOOPSIfbutton) FreeClass(BOOPSIfbutton) ;
  304. }
  305.  
  306. ULONG SAVEDS STDARGS dispatchFButton( Class *cl, Object *o, Msg msg)
  307. {
  308. FButtonINST *inst ;
  309. ULONG       retval = FALSE ;
  310. Object      *object ;
  311.  
  312.     GETA4 ;
  313.     switch (msg->MethodID) {
  314.     case OM_NEW:
  315.         if (object = (Object *)DoSuperMethodA(cl, o, msg)) {
  316.             inst = (FButtonINST *)INST_DATA(cl, object) ;
  317.             if ( FindTagItem(GA_Image, ((opSet *)msg)->ops_AttrList)) {
  318.                 inst->Img = (Image *)GetTagData(GA_Image,
  319.                     NULL,
  320.                     ((opSet *)msg)->ops_AttrList) ;
  321.             }
  322.             inst->XPens = (UWORD *)GetTagData(EGA_XPens, NULL,
  323.                     ((opSet *)msg)->ops_AttrList) ;
  324.             if ( FindTagItem(GA_Text, ((opSet *)msg)->ops_AttrList)) {
  325.                 inst->Text = (STRPTR)GetTagData(GA_Text,
  326.                     NULL,
  327.                     ((opSet *)msg)->ops_AttrList) ;
  328.                 inst->Mode = DRAW_TEXT ;
  329.             }
  330.             else if ( FindTagItem(GA_LabelImage, ((opSet *)msg)->ops_AttrList)) {
  331.                 inst->LabelImage = (Image *)GetTagData(GA_LabelImage,
  332.                     NULL,
  333.                     ((opSet *)msg)->ops_AttrList) ;
  334.                 inst->Mode = DRAW_IMAGE ;
  335.             }
  336.             else if ( FindTagItem(GA_IntuiText, ((opSet *)msg)->ops_AttrList)) {
  337.                 inst->IText = (IntuiText *)GetTagData(GA_IntuiText,
  338.                     NULL,
  339.                     ((opSet *)msg)->ops_AttrList) ;
  340.                  inst->Mode = DRAW_INTUITEXT ;
  341.             }
  342.             else inst->Mode = DRAW_NONE ;
  343.             retval = (ULONG)object ;
  344.         }
  345.         break ;
  346.     case GM_HITTEST:
  347.         retval = DoSuperMethodA(cl, o, msg) ;
  348.         break ;
  349.     case GM_GOACTIVE:
  350.         {
  351.         gpInput *gpi = (gpInput *)msg ;
  352.             if (gpi->gpi_IEvent) {
  353.                 ((Gadget *)o)->Flags |= GFLG_SELECTED ;
  354.                 RenderFButton(cl, (Gadget *)o, (gpRender *)msg) ;
  355.                 retval = GMR_MEACTIVE ;
  356.             }
  357.             else
  358.                 retval = GMR_NOREUSE ;
  359.         }
  360.         break ;
  361.     case GM_GOINACTIVE:
  362.         ((Gadget *)o)->Flags &= ~GFLG_SELECTED ;
  363.         RenderFButton(cl, (Gadget *)o, (gpRender *)msg) ;
  364.         break ;
  365.     case GM_HANDLEINPUT:
  366.         {
  367.             gpInput *gpi = (gpInput *)msg ;
  368.             InputEvent *ie = gpi->gpi_IEvent ;
  369.             Gadget *g = (Gadget *)o ;
  370.             retval = GMR_MEACTIVE ;
  371.  
  372.             if (ie->ie_Class == IECLASS_RAWMOUSE) {
  373.                 switch (ie->ie_Code) {
  374.                     case SELECTUP:
  375.                         if ( (gpi->gpi_Mouse.X < 0) ||
  376.                            (gpi->gpi_Mouse.X > g->Width) ||
  377.                            (gpi->gpi_Mouse.Y < 0) ||
  378.                            (gpi->gpi_Mouse.Y > g->Height) ) {
  379.                                 retval = GMR_NOREUSE  ;
  380.                             }
  381.                         else {
  382.                             NotifyFButton(cl, o, 0, 0, (gpInput *)msg) ;
  383.                             retval = GMR_NOREUSE | GMR_VERIFY ;
  384.                         }
  385.                         break ;
  386.                     case MENUDOWN:
  387.                         retval = GMR_REUSE ;
  388.                         break ;
  389.                     default:
  390.                         retval = GMR_MEACTIVE ;
  391.                 }
  392.             }
  393.             else if (ie->ie_Class == IECLASS_TIMER) {
  394.                 if (( (gpi->gpi_Mouse.X < 0) ||
  395.                    (gpi->gpi_Mouse.X > g->Width) ||
  396.                    (gpi->gpi_Mouse.Y < 0) ||
  397.                    (gpi->gpi_Mouse.Y > g->Height) )) {
  398.                     if (g->Flags & GFLG_SELECTED) {
  399.                         g->Flags &= ~GFLG_SELECTED ;
  400.                         RenderFButton(cl, g, (gpRender *)msg) ;
  401.                     }
  402.                 }
  403.                 else {
  404.                     if (!(g->Flags & GFLG_SELECTED)) {
  405.                         g->Flags |= GFLG_SELECTED ;
  406.                         NotifyFButton(cl, o, OPUF_INTERIM, 0, (gpInput *)msg) ;
  407.                         RenderFButton(cl, g, (gpRender *)msg) ;
  408.                     }
  409.                 }
  410.             }
  411.         }
  412.         break ;
  413.     case OM_SET:
  414.         retval = DoSuperMethodA(cl, o, msg) ;
  415.         if ( FindTagItem(GA_Text, ((opSet *)msg)->ops_AttrList) ||
  416.              FindTagItem(GA_IntuiText, ((opSet *)msg)->ops_AttrList) ||
  417.              FindTagItem(GA_LabelImage, ((opSet *)msg)->ops_AttrList) ) {
  418.             RastPort *rp ;
  419.             Gadget *g  = (Gadget *)o ;
  420.  
  421.             inst = (FButtonINST *)INST_DATA(cl, o) ;
  422.  
  423.             if ( FindTagItem(GA_Text, ((opSet *)msg)->ops_AttrList)) {
  424.                 inst->Text = (STRPTR)GetTagData(GA_Text,
  425.                     (ULONG)inst->Text,
  426.                     ((opSet *)msg)->ops_AttrList) ;
  427.                 inst->Mode = DRAW_TEXT ;
  428.             }
  429.             else if ( FindTagItem(GA_LabelImage, ((opSet *)msg)->ops_AttrList)) {
  430.                 inst->LabelImage = (Image *)GetTagData(GA_LabelImage,
  431.                     (ULONG)inst->LabelImage,
  432.                     ((opSet *)msg)->ops_AttrList) ;
  433.                 inst->Mode = DRAW_IMAGE ;
  434.             }
  435.             else if ( FindTagItem(GA_IntuiText, ((opSet *)msg)->ops_AttrList)) {
  436.                 inst->IText = (IntuiText *)GetTagData(GA_IntuiText,
  437.                     (ULONG)inst->IText,
  438.                     ((opSet *)msg)->ops_AttrList) ;
  439.                  inst->Mode = DRAW_INTUITEXT ;
  440.             }
  441.             if (rp = ObtainGIRPort( ((opSet *)msg)->ops_GInfo) ) {
  442.  
  443.                 DoMethod(o, GM_RENDER, ((opSet *)msg)->ops_GInfo, rp, GREDRAW_REDRAW) ;
  444.                 ReleaseGIRPort(rp) ;
  445.             }
  446.         }
  447.         break ;
  448.     case GM_RENDER:
  449.         retval = RenderFButton(cl, (Gadget *)o, (gpRender *)msg) ;
  450.         break ;
  451.     default :
  452.         retval = DoSuperMethodA(cl, o, msg) ;
  453.         break ;
  454.     }
  455.     return retval ;
  456. }
  457.  
  458.  
  459. void SAVEDS NotifyFButton(Class *cl, Object *o, ULONG flags, long level, gpInput *gpi)
  460. {
  461. static TagItem tt[3] ;
  462.  
  463.     GETA4 ;
  464.     tt[0].ti_Tag = EGA_Pulse ;
  465.     tt[0].ti_Data = level  ;
  466.  
  467.     tt[1].ti_Tag = GA_ID ;
  468.     tt[1].ti_Data = ((Gadget *)o)->GadgetID ;
  469.  
  470.     tt[2].ti_Tag = TAG_DONE ;
  471.  
  472.     DoSuperMethod(cl, o, OM_NOTIFY, tt, gpi->gpi_GInfo, flags) ;
  473. }
  474.  
  475. ULONG SAVEDS RenderFButton(Class *cl, Gadget *g, gpRender *msg)
  476. {
  477. RastPort    *rp ;
  478. ULONG       retval = TRUE ;
  479. UWORD       *pens = msg->gpr_GInfo->gi_DrInfo->dri_Pens ;
  480. FButtonINST *inst = (FButtonINST *)INST_DATA(cl, (Object *)g) ;
  481. ULONG       state ;
  482. impDraw     imp ;
  483. IntuiText   *itext ;
  484. LONG        l, t ;
  485. IBox        cbox, fbox ;
  486. impFrameBox ifb ;
  487.  
  488.     GETA4 ;
  489.     if (msg->MethodID == GM_RENDER)
  490.         rp = msg->gpr_RPort ;
  491.     else
  492.         rp = ObtainGIRPort(msg->gpr_GInfo) ;
  493.     if (rp) {
  494.  
  495.         if (g->Flags & GFLG_SELECTED)
  496.             state = IDS_SELECTED ;
  497.         else if (g->Flags & GFLG_DISABLED)
  498.             state = IDS_DISABLED ;
  499.         else
  500.             state = IDS_NORMAL ;
  501.  
  502.         cbox.Left = g->LeftEdge ;
  503.         cbox.Top = g->TopEdge ;
  504.         cbox.Width = g->Width ;
  505.         cbox.Height = g->Height ;
  506.  
  507.         ifb.MethodID = IM_FRAMEBOX ;
  508.         ifb.imp_ContentsBox = &cbox ;
  509.         ifb.imp_FrameBox = &fbox ;
  510.         ifb.imp_DrInfo = msg->gpr_GInfo->gi_DrInfo ;
  511.         ifb.imp_FrameFlags = NULL ;
  512.         DoMethodA((Object *)inst->Img, (Msg)&ifb) ;
  513.  
  514.         SetAPen(rp, (g->Flags & GFLG_SELECTED)?pens[FILLPEN]:inst->XPens[BUTTONFILL_PEN]) ;
  515.         RectFill(rp, g->LeftEdge, g->TopEdge,
  516.             g->LeftEdge+g->Width-1, g->TopEdge+g->Height-1) ;
  517.  
  518.         imp.MethodID = IM_DRAWFRAME ;
  519.         imp.imp_RPort = rp ;
  520.         imp.imp_Offset.X = g->LeftEdge ;
  521.         imp.imp_Offset.Y = g->TopEdge ;
  522.         imp.imp_State = state ;
  523.         imp.imp_DrInfo = msg->gpr_GInfo->gi_DrInfo ;
  524.         imp.imp_Dimensions.Width = g->Width ;
  525.         imp.imp_Dimensions.Height = g->Height ;
  526.  
  527.         DoMethodA((Object *)inst->Img, (Msg)&imp) ;
  528.  
  529.         if (state == IDS_DISABLED) {
  530.             SetAPen(rp, 1) ;
  531.             SetAfPt(rp, ditherData, 1) ;
  532.             RectFill(rp, g->LeftEdge, g->TopEdge, g->LeftEdge+g->Width-1, g->TopEdge+g->Height-1) ;
  533.             SetAfPt(rp, NULL, 0) ;
  534.         }
  535.  
  536.         switch (inst->Mode) {
  537.         case DRAW_NONE:
  538.             break ;
  539.         case DRAW_TEXT:
  540.             Move(rp, g->LeftEdge, g->TopEdge+rp->TxBaseline) ;
  541.             Text(rp, inst->Text, strlen(inst->Text)) ;
  542.             break ;
  543.         case DRAW_INTUITEXT:
  544.             itext = inst->IText ;
  545.             while (itext->NextText) itext = itext->NextText ;
  546.             l = IntuiTextLength(itext) + itext->LeftEdge ;
  547.             l = g->LeftEdge + 1 + (g->Width - l - 2) / 2 ;
  548.             t = g->TopEdge + 1 + (g->Height - itext->ITextFont->ta_YSize -2) / 2 ;
  549.             PrintIText(rp, inst->IText, l, t) ;
  550.             break ;
  551.         case DRAW_IMAGE:
  552.             // ne pas afficher les images trop grandes pour le gadget
  553.  
  554.             if (inst->LabelImage->Width < g->Width &&
  555.                 inst->LabelImage->Height < g->Height) {
  556.  
  557.             // Centrage de l'image
  558.             l = g->LeftEdge + (g->Width - inst->LabelImage->Width) /  2 ;
  559.             t = g->TopEdge + (g->Height - inst->LabelImage->Height) /  2 ;
  560.             DrawImageState(rp,
  561.                 inst->LabelImage,
  562.                 l, t,
  563.                 state,
  564.                 msg->gpr_GInfo->gi_DrInfo) ;
  565.             }
  566.             break ;
  567.         }
  568.         if (msg->MethodID != GM_RENDER)
  569.             ReleaseGIRPort(rp) ;
  570.  
  571.     }
  572.     else
  573.         retval = FALSE ;
  574.     return retval ;
  575. }
  576.  
  577.  
  578.